import csv
from flask import Flask, render_template, request, jsonify, Response
import requests
import json
import pandas as pd
import plotly
import openai

from models.ARIMA import *  
from models.LightGBMDemo import train_and_predict

import os
import plotly.graph_objs as go

from utils.common_utils import clear_json_content
from utils.user_utils import insert_user_csv, draw
from utils.common_utils import clear_csv_content
from utils.fault_utils import predict_fault_probabilities, calculate_fault_percentages

app = Flask(__name__, template_folder='templates')

# DeepSeek 服务器信息
DEESEEK_URL = "http://10.181.8.236:9988/v1/completions"  # 确保 URL 正确
API_KEY = "7183ds"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

@app.route('/ai')
def toAi():
    return render_template('ai.html')

@app.route('/ai/talk', methods=['POST'])
def ai_talk():
    user_input = request.json.get("message", "")
    selected_preset = request.json.get("preset", "preset_prompt_1")

    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }
    preset_prompts = {
        "preset_prompt_1" : "你是一个专业的前台助手，现在客户将向你提问，你不需要回答，只需要根据客户的提问，将该问题分类为“购买力预测”、“售价管理”、“用户画像”、“库存管理”、“故障预警”中的一个，并输出给我，而且只需要根据你的判断输出概率最高的种类。以下是用户的问题：",
        "preset_prompt_2" : "你是一个机器学习领域专家，现在我将为你提供我的模型和参数列表，请帮助我选择合适的参数。模型和参数如下："
    }

    prompt = preset_prompts.get(selected_preset, "")

    data = {
        "model": "/data/huggingface/deepseek-ai/DeepSeek-R1-Distill-Llama-8B",
        "prompt": prompt + user_input,
        "max_tokens": 10000,
        "stream": True  # **启用流式响应**
    }


    def get_final_category():
        collected_text = ""

        with requests.post(DEESEEK_URL, json=data, headers=headers, stream=True) as response:
            for line in response.iter_lines():
                if line:
                    try:
                        line = line.decode("utf-8").strip()
                        if line.startswith("data:"):
                            line = line[5:].strip()
                        json_data = json.loads(line)

                        if "choices" in json_data and len(json_data["choices"]) > 0:
                            text = json_data["choices"][0]["text"]
                            collected_text += text
                    except json.JSONDecodeError:
                        continue

        # 全部收集完毕后再进行分类提取
        # 全部收集完毕后再进行分类提取
        CATEGORIES = ["购买力预测", "售价管理", "用户画像", "库存管理", "故障预警"]

        # 提取 </think> 标签之后的内容
        if "</think>" in collected_text:
            post_think_text = collected_text.split("</think>", 1)[1].strip()
        else:
            post_think_text = collected_text.strip()

        # 在 think 标签之后查找最可能的分类
        for category in CATEGORIES:
            if category in post_think_text:
                return category

        return "未知分类"

    # 直接交互响应输出流
    def stream_response():
        with requests.post(DEESEEK_URL, json=data, headers=headers, stream=True) as response:
            for line in response.iter_lines():
                if line:
                    # 解析 JSON 格式的行
                    try:
                        line = line.decode("utf-8").strip()
                        if line.startswith("data:"):
                            line = line[5:].strip()  # 去掉前面的 "data:"
                        json_data = json.loads(line)

                        # 提取文本
                        if "choices" in json_data and len(json_data["choices"]) > 0:
                            text = json_data["choices"][0]["text"]
                            yield text  # 直接返回文本
                    except json.JSONDecodeError:
                        continue  # 解析错误时跳过

    if selected_preset == "preset_prompt_1":
        return Response(get_final_category(), content_type="text/plain; charset=utf-8")

    return Response(stream_response(), content_type="text/plain; charset=utf-8")



# 启动项目
@app.route('/')
def index():
    return render_template('test.html')



@app.route('/home')
def gohome():
    return render_template('index.html')


# 购买力预测相关模型与接口
@app.route('/view/purchasing')
def to_view_purchasing():
    return render_template('purchasing.html')


@app.route('/run_arima', methods=['POST'])
def run_arima():
    data = request.get_json()
    p = int(data['p'])
    d = int(data['d'])
    q = int(data['q'])
    steps = int(data['steps'])
    perform_arima_prediction(p, d, q, steps,
                             data_file='data/purchasing/test2.json',
                             forecast_file='data/purchasing/test3.json')
    return "预测数据已生成(ARIMA)"


@app.route('/run_lightGBM', methods=['POST'])
def run_lightGBM():
    data = request.get_json()
    boosting_type = str(data['boosting_type'])
    learning_rate = float(data['learning_rate'])
    feature_fraction = float(data['feature_fraction'])
    bagging_fraction = float(data['bagging_fraction'])
    train_and_predict(boosting_type, learning_rate, feature_fraction, bagging_fraction,
                      data_file='data/purchasing/test2.json',
                      forecast_file='data/purchasing/test3.json')
    return "预测数据已生成(lightGBM)"


@app.route('/process_data', methods=['GET'])
def process_data():
    data_path = 'data/purchasing/test2.json'
    forecast_path = 'data/purchasing/test3.json'

    with open(data_path, 'r') as file:
        original_data = json.load(file)

    df_original = pd.DataFrame(original_data)

    # Create initial line plot for original data
    fig = go.Figure()
    fig.add_scatter(x=df_original['x'], y=df_original['y'], mode='lines', name='原始数据', line=dict(color='blue'))

    # Attempt to add forecast data or create an empty line for the legend
    if os.path.exists(forecast_path) and os.path.getsize(forecast_path) > 0:
        with open(forecast_path, 'r') as file:
            forecast_data = json.load(file)
            if forecast_data:
                df_forecast = pd.DataFrame(forecast_data)
                fig.add_scatter(x=df_forecast['x'], y=df_forecast['y'], mode='lines', name='预测数据',
                                line=dict(color='red'))
            else:
                # Ensure the legend item for forecast data is displayed even if it's empty
                fig.add_scatter(x=[], y=[], mode='lines', name='Forecast Data', line=dict(color='red'))
    graphJSON = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
    return jsonify(graph_json=json.loads(graphJSON))


@app.route('/clear', methods=['POST'])
def purchasing_clear():
    clear_json_content('data/purchasing/test3.json')
    return "预测数据已清空"


# 用户预测相关模型与接口
@app.route('/view/user')
def to_view_user():
    return render_template('user.html')


@app.route('/user/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return 'No file part'

    file = request.files['file']
    if file.filename == '':
        return 'No selected file'

    if file and file.filename.endswith('.csv'):
        filename = 'data/user/original_data.csv'
        file.save(os.path.join(os.getcwd(), filename))
        return 'File uploaded successfully'

    return 'Invalid file type'


@app.route('/user/insert', methods=['POST'])
def insert_user():
    data = request.get_json()
    # 这里调用你的insert_user_csv函数
    new_data = {
        'Gender': str(data['Gender']),
        'Age': int(data['Age']),
        'Annual Income (k$)': int(data['Annual Income (k$)']),
        'Spending Score (1-100)': int(data['Spending Score (1-100)'])
    }
    insert_user_csv(new_data, "data/user/new_data.csv")
    return jsonify({'message': 'Data inserted successfully!'})


@app.route('/user/clear', methods=['POST'])
def user_clear():
    clear_csv_content('data/user/new_data.csv')
    return "新增数据已经删除"


@app.route('/user/draw', methods=['POST'])
def user_draw():
    data = request.get_json()
    method = data.get('method')
    if not method:
        return jsonify({'error': '缺少模型参数'}), 400

    draw(method)
    return "已重新绘制图像"


@app.route('/view/inventory')
def to_view_inventory():
    return render_template('inventory.html')


@app.route('/view/fault')
def to_view_fault():
    return render_template('fault.html')


# @app.route('/fault/predict', methods=['POST'])
# def get_fault_data():
#     threshold_x = float(request.form['threshold_x'])
#     normal_percentage, fault_percentages = calculate_fault_percentages("data/fault/predictions.csv", threshold_x)
#     data = {
#     'normal': normal_percentage,
#     'faults': fault_percentages
#     }
#     return jsonify(data)

@app.route('/fault/draw', methods=['POST'])
def get_fault_data():
    threshold_x = float(request.form['threshold_x'])
    normal_percentage, fault_percentages = calculate_fault_percentages("data/fault/predictions.csv", threshold_x)
    data = {
        'normal': normal_percentage,
        'faults': fault_percentages
    }
    return jsonify(data)


@app.route('/fault/search', methods=['GET'])
def fault_search():
    # 获取查询参数中的 id
    search_id = request.args.get('id', type=int)
    # 加载预测结果的 CSV 文件
    predictions_file = "data/fault/predictions.csv"
    if not os.path.exists(predictions_file):
        return jsonify({"error": "预测结果文件不存在,请先生成"}), 404

    predictions_df = pd.read_csv(predictions_file)

    # 根据 id 搜索对应的行
    result = predictions_df[predictions_df['id'] == search_id]

    # 如果找到了结果，返回该行的数据
    if not result.empty:
        return jsonify(result.to_dict(orient='records'))
    else:
        return jsonify({"error": "未找到对应的 ID"}), 404




@app.route('/view/price')
def to_view_price():
    return render_template('price.html')


@app.route('/a', methods=['GET'])
def getaicp():
    results = get_AIC(10)
    x_data = [item['p'] for item in results]
    z_data = [item['AIC'] for item in results]
    
    xmin = min(x_data) - 1
    xmax = max(x_data) + 1
    zmin = min(z_data) * 0.8
    zmax = max(z_data) * 1.2

    plotly_data = {
        "x": x_data,
        "y": z_data,
        "xmin" : xmin,
        "xmax" : xmax,
        "ymin" : zmin,
        "ymax" : zmax,
        "type": "bar"
    }
    return jsonify(plotly_data)

@app.route('/b', methods=['GET'])
def getaicq():
    results = get_AICb(10)
    x_data = [item['q'] for item in results]
    z_data = [item['AIC'] for item in results]
    
    xmin = min(x_data) - 1
    xmax = max(x_data) + 1
    zmin = min(z_data) * 0.8
    zmax = max(z_data) * 1.2

    plotly_data = {

        "x": x_data,
        "y": z_data,
        "xmin" : xmin,
        "xmax" : xmax,
        "ymin" : zmin,
        "ymax" : zmax,
        "type": "bar"
    }
    return jsonify(plotly_data)


def read_csv_inventory(file_path):
    data = []
    with open(file_path, mode='r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        data = [
            {
                "name": row["name"],
                "longitude": float(row["longitude"]),
                "latitude": float(row["latitude"]),
                "inventory": int(row["inventory"]),
                "demand": int(row["demand"])
            }
            for row in reader
        ]
    return data

@app.route('/get_inventory_data', methods=['POST'])
def get_inventory_data():
    dataset = request.form['dataset']
    file_path = f'data/inventory/inventory{dataset}.csv'
    data = read_csv_inventory(file_path)
    
    # 计算库存与需求的比率
    for item in data:
        item["ratio"] = item["inventory"] / item["demand"] if item["demand"] != 0 else 0

    # print(data)
    return jsonify(data)

if __name__ == '__main__':
    app.run(debug=True)
